package com.binc.testspring.study.nio.netty.protocoltcp;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelOption;
import io.netty.channel.FixedRecvByteBufAllocator;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.extern.slf4j.Slf4j;

/**
 * FileName: Server   自定义编解码
 * Autho: binC
 * Date:  2022/4/21 14:27
 */
@Slf4j
public class Server {
    final static int PORT = 8888;

    public static void main(String[] args) throws InterruptedException {
        //创建BossGroup 和 WorkerGroup

        NioEventLoopGroup bossGroup = new NioEventLoopGroup(1);
        NioEventLoopGroup workGroup = new NioEventLoopGroup(); // 没有参数试试创建8个子线程数
        try {

            //创建服务器端的启动对象,并配置参数
            ServerBootstrap serverBootstrap = new ServerBootstrap();

            //使用链式编程对启动对象进行设置
            serverBootstrap
                    // .option(ChannelOption.SO_RCVBUF,30) // 这是限制buffer长度为30   为了演示半包
                    .option(ChannelOption.RCVBUF_ALLOCATOR,new FixedRecvByteBufAllocator(30))
                    //FixedRecvByteBufAllocator也可以换为AdaptiveRecvByteBufAllocator  第一种参数似乎不起作用，找到了这个issue，根据里面的说法，这个参数传到os层，由于不同os的差异，实际上这个参数未必会和设置的一样，最终缓冲区大小还是由os决定的。

                    .group(bossGroup, workGroup) // 服务端启动对象设置两个线程组       客户端的只需要设置一个
                    .channel(NioServerSocketChannel.class) // 使用NioServerSocketChannel作为服务器的通道实现
                    .option(ChannelOption.SO_BACKLOG, 128) // 设置线程队列等待连接个数
                    // .handler(null) // 该handler来对应bossGroup;   childHandler 对应workerGroup
                    .childOption(ChannelOption.SO_KEEPALIVE, true) // 设置包hi活动连接状态
                    .childHandler(new MyServerChannelInit()); // channel初始化不用匿名对象了,单独建立一个对象Mychannelinit

            log.info("===== 服务器端 设置完成了=====");

            //绑定一个端口并且同步生成了一个 ChannelFuture 对象（也就是立马返回这样一个对象）
            //启动服务器(并绑定端口)
            ChannelFuture channelFuture = serverBootstrap.bind(PORT);

            //给channelFuture 注册监听器，监控我们关心的事件
            channelFuture.addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture cf) throws Exception {
                    if (cf.isSuccess()) {
                        log.info("=====监听端口{}成功=====", PORT);
                    } else {
                        log.info("=====监听端口{}失败=====", PORT);
                    }
                }
            });

            //对关闭通道时间进行监听
            channelFuture.channel().closeFuture().sync();

        }finally {
            bossGroup.shutdownGracefully();
            workGroup.shutdownGracefully();
        }

    }


}
